package com.hotelsystem.aop;

import com.alibaba.fastjson.JSON;
import com.hotelsystem.pojo.Employee;
import com.hotelsystem.pojo.Logging;
import com.hotelsystem.service.LoggingService;
import com.hotelsystem.util.ConstantValue;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;


@Aspect
@Component
public class WebLogAcpect {

    //注入日志业务层

    @Resource(name = "loggingServiceImpl")
    private LoggingService loggingService;

    //获取日志对象
    private Logger logger = LoggerFactory.getLogger(WebLogAcpect.class);



    /**
     * 定义切入点,切点为com.example.demo.aop的所有函数
     */
    @Pointcut("execution(public * com.hotelsystem.controller..*.*(..)) && !execution(public * com.hotelsystem.controller.EmployeeController.login(..)) && !execution(public * com.hotelsystem.controller.LoggingController.toLogging(..)))")
    public  void webLog(){}

    /**
     * 环绕通知：
     *   环绕通知非常强大，可以决定目标方法是否执行，什么时候执行，执行时是否需要替换方法参数，执行完毕是否需要替换返回值。
     *   环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
     */
    @Around("webLog()")
    public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Exception {


        //用的最多 通知的签名
        Signature signature = proceedingJoinPoint.getSignature();
        logger.info("环绕通知的目标方法名："+ signature.getName());
        logger.info("AOP代理类的名字"+signature.getDeclaringTypeName()); //调用了 那个类

        //AOP代理类的类（class）信息
        signature.getDeclaringType();
        //获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();

        //如果要获取Session信息的话，可以这样写：
        HttpSession session = (HttpSession) requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION);
        //获取请求参数
        Enumeration<String> enumeration = request.getParameterNames();
        Map<String,String> parameterMap = new HashMap<>();
        while (enumeration.hasMoreElements()){
            String parameter = enumeration.nextElement();
            parameterMap.put(parameter,request.getParameter(parameter));
        }
        String str = JSON.toJSONString(parameterMap);//传入的参数
        String strMessage = null;
        try {
            Object obj = proceedingJoinPoint.proceed();

            //用户操作的信息 操作了那个类的那个方法 传入的参数是什么
            strMessage = "操作了"+signature.getDeclaringTypeName()+"的类的"+signature.getName()+"方法，"+"执行结果：成功！";
            return obj;
        } catch (Throwable throwable) {
            strMessage = "操作了"+signature.getDeclaringTypeName()+"的类的"+signature.getName()+"方法，"+"执行结果：失败"+"原因："+throwable.getMessage();
            // logger.info("原因："+throwable.getMessage());

        }finally {
            System.out.println(strMessage);
            //在这里判断会话如果为空 就不执行操作
            //为什么会出现这个问题呢？原因拦截器哪里shiro验证出现问题，因为是aop面向切面，执行条件时，会先执行这个
            //直接在合理判断，让他跳转
            Employee employee = (Employee) session.getAttribute(ConstantValue.LOGIN_USER);
            if ( employee != null && employee.getUsername()!=null){
            Logging logging = new Logging();
            //保存日期
            logging.setCreateDate(new Date());
            logging.setOperator(employee.getUsername());
            //在这里执行数据库操作 直接盗用工具类
            logging.setMessage(strMessage);
            loggingService.insert(logging);
            }
        }
        return null;
    }

}

